*** do-file for ejpr paper (forthcoming)
** title: dynamics of protest and electoral politics in the great recession
** authors: björn bremer (bremer@mpifg.de), swen hutter and hanspeter kriesi
** description: analyse the pm-level data to create results for the main analysia and appendix
** last updated: 13 October 2019

clear
set more off 
cd "" // set your local working directory which contains the folders with a sub-folder for the data, graphs, tables, and appendix here

**---------------------------------------
*** set the scheme for the graphs
**---------------------------------------

*ssc install blindschemes, replace
set scheme  plottigblind
set scheme plotplainblind

**---------------------------------------
*** load the pm-level dataset
**---------------------------------------

use "./data/data_pm_replication.dta", clear

**---------------------------------------
*** create new and recode existing variables
**---------------------------------------

** create the misery factor
factor gdp_change unemployment_change debt_change 
predict misery

** create a simple election number count
recode election_number (-1 0 = 0) (1 = 1) (2 3 4 5 = 2), gen(election_simple)

** recode electoral loss into positive values
gen elect_loss = pm_vote_change*(-1)

** weight protest for duration of the legislative period
gen wevent_dur = wevent/duration
gen wpart_dur = lpopw_part_all/duration

gen react_wevent_dur = react_wevent/duration
gen react_wpart_dur = react_lpopw_part_all/duration

** standardise variables
egen z2_wevent = std(wevent_dur)
egen z2_wpart = std(wpart_dur)
egen z2_react_wevent = std(react_wevent_dur)
egen z2_react_wpart = std(react_lpopw_part_all)
egen z2_elect_loss = std(elect_loss)
egen z2_misery = std(misery)
egen z2_unemployment_change = std(unemployment_change)
egen z2_debt_change = std(debt_change)
egen z2_gdp_change = std(gdp_change)

** relabel variables
lab var z2_elect_loss "Electoral loss"
lab var z2_wevent "Protest"
lab var z2_wpart "Protest"
lab var z2_misery "Misery"
lab var z2_unemployment_change "Unempl."
lab var z2_debt_change "Debt"
lab var z2_gdp_change "GDP"

lab var pm_t_vote "Vote share (t-1)"
lab var misery "Misery"
lab var elect_loss "Electoral loss"
lab var wevent "Protest"

lab var election_simple "Election"
lab def election_simple 0 "Pre-crisis elec." 1 "First crisis elec." 2 "Later crisis elec."
lab val election_simple election_simple

lab var east "Eastern Europe"
lab def east 0 "Not Eastern Europe" 1 "Eastern Europe" 
lab val east east

**---------------------------------------
*** table 2: use electoral loss and protest as dv
**---------------------------------------

cd "./tables/"

eststo clear

eststo: quietly regress z2_elect_loss z2_misery 
eststo: quietly regress z2_wevent z2_misery

eststo: quietly regress z2_elect_loss c.z2_misery##i.election_simple
eststo: quietly regress z2_wevent c.z2_misery##i.election_simple 

eststo: quietly regress z2_elect_loss z2_misery if east == 0 
eststo: quietly regress z2_wevent z2_misery if east == 0 

eststo: quietly regress z2_elect_loss c.z2_misery##i.election_simple if east == 0 
eststo: quietly regress z2_wevent c.z2_misery##i.election_simple if east == 0 

esttab using table2.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery on electoral loss and protest)

**---------------------------------------
*** table 3: use protest as iv
**---------------------------------------

eststo clear

eststo: quietly regress z2_elect_loss z2_misery
eststo: quietly regress z2_elect_loss z2_misery z2_wevent
eststo: quietly regress z2_elect_loss c.z2_misery##c.z2_wevent

eststo: quietly regress z2_elect_loss z2_misery if east == 0
eststo: quietly regress z2_elect_loss z2_misery z2_wevent if east == 0
eststo: quietly regress z2_elect_loss c.z2_misery##c.z2_wevent if east == 0

esttab using table3.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery and protest on electoral loss)

**---------------------------------------
*** create marginal effect plots
**---------------------------------------

cd "../graphs/"

** figure 1a: average marginal effects for electoral loss (all)
regress z2_elect_loss c.z2_misery##i.election_simple
margins, dydx(z2_misery) over(election_simple)
marginsplot, recast(scatter) recastci(rspike) ///
yline(0) xlabel(-.25 " " 0 "Pre-crisis" 1 "First crisis" 2 "Later crisis" 2.25 " ", notick nogrid labsize(medlarge)) ylabel(-0.5 (0.5) 2, grid labsize(medlarge)) ///
level(83) aspectratio(1.25) ysize(4) xsize(3.5) title("") ytitle("Average marginal effect of misery", size(medlarge)) xtitle("Election type", size(medlarge))
graph export figure1a.eps, replace

** figure 1b: compute average marginal effects for electoral loss (only WE)
regress z2_elect_loss c.z2_misery##i.election_simple if east == 0
margins, dydx(z2_misery) over(election_simple)
marginsplot, recast(scatter) recastci(rspike) ///
yline(0) xlabel(-.25 " " 0 "Pre-crisis" 1 "First crisis" 2 "Later crisis" 2.25 " ", notick nogrid labsize(medlarge)) ylabel(-0.5 (0.5) 2, grid labsize(medlarge)) ///
level(83) aspectratio(1.25) ysize(4) xsize(3.5) title("") ytitle("Average marginal effect of misery", size(medlarge)) xtitle("Election type", size(medlarge))
graph export figure1b.eps, replace

** figue 1c: compute average marginal effects for protest (all)
regress z2_wevent c.z2_misery##i.election_simple
margins, dydx(z2_misery) over(election_simple)
marginsplot, recast(scatter) recastci(rspike) ///
yline(0) xlabel(-.25 " " 0 "Pre-crisis" 1 "First crisis" 2 "Later crisis" 2.25 " ", notick nogrid labsize(medlarge)) ylabel(-0.5 (0.5) 2, grid labsize(medlarge)) ///
level(83) aspectratio(1.25) ysize(4) xsize(3.5) title("") ytitle("Average marginal effect of misery", size(medlarge)) xtitle("Election Type", size(medlarge))
graph export figure1c.eps, replace

** figure 1d: compute average marginal effects for protest (only WE)
regress z2_wevent c.z2_misery##i.election_simple if east == 0
margins, dydx(z2_misery) over(election_simple)
marginsplot, recast(scatter) recastci(rspike) ///
yline(0) xlabel(-.25 " " 0 "Pre-crisis" 1 "First crisis" 2 "Later crisis" 2.25 " ", notick nogrid labsize(medlarge)) ylabel(-0.5 (0.5) 2, grid labsize(medlarge)) ///
level(83) aspectratio(1.25) ysize(4) xsize(3.5) title("") ytitle("Average marginal effect of misery", size(medlarge)) xtitle("Election Type", size(medlarge))
graph export figure1d.eps, replace

** figure 2a: interaction of protest and misery (all)
regress z2_elect_loss c.z2_wevent##c.z2_misery
margins, dydx(z2_misery) at(z2_wevent=(-1 (0.1) 6.5))
marginsplot, ysc(r(-0.5 2)) ylabel(-0.5 (0.5) 2) xsize(6) ysize(5) xlabel(-1 (1) 6.5) level(95) title("") ytitle("Average marginal effect of misery", size(medlarge)) recast(line) recastci(rarea) ciopts(color(*.5)) yline(0) ylabel(,labsize(medlarge)) xlabel(,labsize(medlarge)) xtitle(,size(medlarge))
graph export figure2a.eps, replace

** figure 2b: interaction of protest and misery (only WE)
regress z2_elect_loss c.z2_wevent##c.z2_misery if east == 0
margins, dydx(z2_misery) at(z2_wevent=(-1 (0.1) 6.5))
marginsplot, ysc(r(-0.5 2)) ylabel(-0.5 (0.5) 2) xsize(6) ysize(5) xlabel(-1 (1) 6.5) level(95) title("") ytitle("Average marginal effect of misery", size(medlarge)) recast(line) recastci(rarea) ciopts(color(*.5)) yline(0) ylabel(,labsize(medlarge)) xlabel(,labsize(medlarge)) xtitle(,size(medlarge))
graph export figure2b.eps, replace

**---------------------------------------
*** appendix: some description of the data
**---------------------------------------

cd "../appendix/"

**---------------------------------------
*** figure a-1: create scatterplots of misery and electoral loss/protest

cd "./graphs/"

** figure a-1a: scatter plot of electoral loss and misery (all)
graph twoway (lfitci z2_elect_loss z2_misery) (scatter z2_elect_loss z2_misery, mcolor(black)), ytitle("Electoral loss", size(medlarge)) title("") xtitle("Misery", size(medlarge)) ylabel(, labsize(medlarge)) xlabel(, labsize(medlarge)) 
graph export figure_a1a.eps, replace

* figure a-1b: scatter plot of electoral loss and misery (only west europe)
graph twoway (lfitci z2_elect_loss z2_misery) (scatter z2_elect_loss z2_misery, mcolor(black)) if east == 0, ytitle("Electoral loss", size(medlarge)) title("") xtitle("Misery", size(medlarge)) ylabel(, labsize(medlarge)) xlabel(, labsize(medlarge))
graph export figure_a1b.eps, replace

** figure a-1c: scatter plot of protest and misery (all)
graph twoway (lfitci z2_wevent z2_misery) (scatter z2_wevent z2_misery, mcolor(black)), ytitle("Relative protest", size(medlarge)) title("") xtitle("Misery", size(medlarge)) ylabel(, labsize(medlarge)) xlabel(, labsize(medlarge)) 
graph export figure_a1c.eps, replace

** figure a-1c: scatter plot of protest and misery (only west europe)
graph twoway (lfitci z2_wevent z2_misery) (scatter z2_wevent z2_misery, mcolor(black)) if east == 0,  ytitle("Relative protest", size(medlarge)) title("") xtitle("Misery", size(medlarge)) ylabel(, labsize(medlarge)) xlabel(, labsize(medlarge))
graph export figure_a1d.eps, replace

**---------------------------------------
*** figure a-2: scatterplots of electoral loss and misery by election type

lab var election_simple "election type"
lab def election_simple 0 "Pre-crisis elections" 1 "First crisis elections" 2 "Later crisis elections", replace
lab val election_simple election_simple

twoway (scatter z2_elect_loss z2_misery, sort mlabel(country_num)) (lfit z2_elect_loss z2_misery, sort mlabel(country_num)), by(election_simple)
graph export figure_a2.eps, replace

**---------------------------------------
*** figure a-3: scatterplots of protest and misery by election type

twoway (scatter z2_wevent z2_misery, sort mlabel(country_num)) (lfit z2_wevent z2_misery, sort mlabel(country_num)), by(election_simple)
graph export figure_a3.eps, replace

**---------------------------------------
*** figure a-4: scatterplots of electoral loss and misery by intensity of protest 

gen protest_high = 1 if z2_wevent > 1
replace protest_high = 0 if protest_high ==.

lab var protest_high "Protest"
lab def protest_high 0 "Low protest" 1 "High protest"
lab val protest_high protest_high

twoway (scatter z2_elect_loss z2_misery, sort mlabel(country_num)) (lfit z2_elect_loss z2_misery, sort mlabel(country_num)), by(protest_high) 
graph export figure_a4.eps, replace

**---------------------------------------
*** appendix: robustness tests
**---------------------------------------

cd "../tables/"

**---------------------------------------
** appendix b-1: estimate models with participants instead of event count

* table b-1:
eststo clear

eststo: quietly regress z2_elect_loss z2_misery
eststo: quietly regress z2_wpart z2_misery

eststo: quietly regress z2_elect_loss c.z2_misery##i.election_simple
eststo: quietly regress z2_wpart c.z2_misery##i.election_simple

eststo: quietly regress z2_elect_loss z2_misery if east == 0
eststo: quietly regress z2_wpart z2_misery if east == 0

eststo: quietly regress z2_elect_loss c.z2_misery##i.election_simple if east == 0
eststo: quietly regress z2_wpart c.z2_misery##i.election_simple if east == 0

esttab using table_b1.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery on electoral loss and protest (participants))

* table b-2:
eststo clear

eststo: quietly regress z2_elect_loss z2_misery
eststo: quietly regress z2_elect_loss z2_misery z2_wpart
eststo: quietly regress z2_elect_loss c.z2_misery##c.z2_wpart

eststo: quietly regress z2_elect_loss z2_misery if east == 0
eststo: quietly regress z2_elect_loss z2_misery z2_wpart if east == 0
eststo: quietly regress z2_elect_loss c.z2_misery##c.z2_wpart if east == 0

esttab using table_b2.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery and protest on electoral loss (participants))

**---------------------------------------
** appendix b-1: estimate models with unemployment instead of misery

* table b-4:
eststo clear

eststo: quietly regress z2_elect_loss z2_unemployment_change
eststo: quietly regress z2_wevent z2_unemployment_change

eststo: quietly regress z2_elect_loss c.z2_unemployment_change##i.election_simple
eststo: quietly regress z2_wevent c.z2_unemployment_change##i.election_simple

eststo: quietly regress z2_elect_loss z2_unemployment_change if east == 0
eststo: quietly regress z2_wevent z2_unemployment_change if east == 0

eststo: quietly regress z2_elect_loss c.z2_unemployment_change##i.election_simple if east == 0
eststo: quietly regress z2_wevent c.z2_unemployment_change##i.election_simple if east == 0

esttab using table_b4.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of unemployment on electoral loss and protest)

* table b-5:
eststo clear

eststo: quietly regress z2_elect_loss z2_unemployment_change
eststo: quietly regress z2_elect_loss z2_unemployment_change z2_wevent
eststo: quietly regress z2_elect_loss c.z2_unemployment_change##c.z2_wevent

eststo: quietly regress z2_elect_loss z2_unemployment_change if east == 0
eststo: quietly regress z2_elect_loss z2_unemployment_change z2_wevent if east == 0
eststo: quietly regress z2_elect_loss c.z2_unemployment_change##c.z2_wevent if east == 0

esttab using table_b5.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of unemployment and protest on electoral loss)

**---------------------------------------
** apendix b-2: use additional control variables

* table b-7:
eststo clear

eststo: quietly regress z2_elect_loss z2_misery pm_t_vote coalition_government switzerland i.bailout
eststo: quietly regress z2_wevent z2_misery pm_t_vote coalition_government switzerland i.bailout

eststo: quietly regress z2_elect_loss c.z2_misery##i.election_simple pm_t_vote coalition_government switzerland i.bailout
eststo: quietly regress z2_wevent c.z2_misery##i.election_simple pm_t_vote coalition_government switzerland i.bailout

eststo: quietly regress z2_elect_loss z2_misery pm_t_vote coalition_government switzerland i.bailout if east == 0
eststo: quietly regress z2_wevent z2_misery pm_t_vote coalition_government switzerland i.bailout if east == 0 

eststo: quietly regress z2_elect_loss c.z2_misery##i.election_simple pm_t_vote coalition_government switzerland i.bailout if east == 0 
eststo: quietly regress z2_wevent c.z2_misery##i.election_simple pm_t_vote coalition_government switzerland i.bailout if east == 0 

esttab using table_b7.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery on electoral loss and protest with additional control variables)

* table b-8:
eststo clear

eststo: quietly regress z2_elect_loss c.z2_misery pm_t_vote coalition_government switzerland i.bailout
eststo: quietly regress z2_elect_loss c.z2_misery z2_wevent pm_t_vote coalition_government switzerland i.bailout
eststo: quietly regress z2_elect_loss c.z2_misery##c.z2_wevent pm_t_vote coalition_government switzerland i.bailout

eststo: quietly regress z2_elect_loss c.z2_misery pm_t_vote coalition_government switzerland i.bailout if east == 0
eststo: quietly regress z2_elect_loss c.z2_misery z2_wevent pm_t_vote coalition_government switzerland i.bailout if east == 0
eststo: quietly regress z2_elect_loss c.z2_misery##c.z2_wevent pm_t_vote coalition_government switzerland i.bailout if east == 0

esttab using table_b8.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery and protest on electoral loss with additional control variables)

**---------------------------------------
** appendix b-3: estimate clustered standard errors

* table b-9:
eststo clear

eststo: quietly regress z2_elect_loss z2_misery, cluster(country_num)
eststo: quietly regress z2_wevent z2_misery, cluster(country_num)

eststo: quietly regress z2_elect_loss c.z2_misery##i.election_simple, cluster(country_num)
eststo: quietly regress z2_wevent c.z2_misery##i.election_simple, cluster(country_num)

eststo: quietly regress z2_elect_loss z2_misery if east == 0, cluster(country_num)
eststo: quietly regress z2_wevent z2_misery if east == 0, cluster(country_num)

eststo: quietly regress z2_elect_loss c.z2_misery##i.election_simple if east == 0, cluster(country_num)
eststo: quietly regress z2_wevent c.z2_misery##i.election_simple if east == 0, cluster(country_num)

esttab using table_b9.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery on electoral loss and protest with country-clustered SEs)

* table b-10:
eststo clear

eststo: quietly regress z2_elect_loss z2_misery, cluster(country_num)
eststo: quietly regress z2_elect_loss z2_misery z2_wevent, cluster(country_num)
eststo: quietly regress z2_elect_loss c.z2_misery##c.z2_wevent, cluster(country_num)

eststo: quietly regress z2_elect_loss z2_misery if east == 0, cluster(country_num)
eststo: quietly regress z2_elect_loss z2_misery z2_wevent if east == 0, cluster(country_num)
eststo: quietly regress z2_elect_loss c.z2_misery##c.z2_wevent if east == 0, cluster(country_num)

esttab using table_b10.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery and protest on electoral loss with country-clustered SEs)

**---------------------------------------
** appendix b-3: use quantile median regression

* table b-12:
eststo clear

eststo: quietly qreg z2_elect_loss z2_misery
eststo: quietly qreg z2_wevent z2_misery

eststo: quietly qreg z2_elect_loss c.z2_misery##i.election_simple
eststo: quietly qreg z2_wevent c.z2_misery##i.election_simple

eststo: quietly qreg z2_elect_loss z2_misery if east == 0
eststo: quietly qreg z2_wevent z2_misery if east == 0

eststo: quietly qreg z2_elect_loss c.z2_misery##i.election_simple if east == 0
eststo: quietly qreg z2_wevent c.z2_misery##i.election_simple if east == 0

esttab using table_b12.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery on electoral loss and protest (quantile regression))

* table b-13:
eststo clear

eststo: quietly qreg z2_elect_loss z2_misery
eststo: quietly qreg z2_elect_loss z2_misery z2_wevent
eststo: quietly qreg z2_elect_loss c.z2_misery##c.z2_wevent

eststo: quietly qreg z2_elect_loss z2_misery if east == 0
eststo: quietly qreg z2_elect_loss z2_misery z2_wevent if east == 0
eststo: quietly qreg z2_elect_loss c.z2_misery##c.z2_wevent if east == 0

esttab using table_b13.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery and protest on electoral loss (quantile regression))


**---------------------------------------
** appendix b-3: estimate robust regressions

* table b-15
eststo clear

eststo: quietly rreg z2_elect_loss z2_misery
eststo: quietly rreg z2_wevent z2_misery

eststo: quietly rreg z2_elect_loss c.z2_misery##i.election_simple
eststo: quietly rreg z2_wevent c.z2_misery##i.election_simple

eststo: quietly rreg z2_elect_loss z2_misery if east == 0
eststo: quietly rreg z2_wevent z2_misery if east == 0

eststo: quietly rreg z2_elect_loss c.z2_misery##i.election_simple if east == 0
eststo: quietly rreg z2_wevent c.z2_misery##i.election_simple if east == 0

esttab using table_b15.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery on electoral loss and protest (robust regression))

* table b-16:
eststo clear

eststo: quietly rreg z2_elect_loss z2_misery
eststo: quietly rreg z2_elect_loss z2_misery z2_wevent
eststo: quietly rreg z2_elect_loss c.z2_misery##c.z2_wevent

eststo: quietly rreg z2_elect_loss z2_misery if east == 0
eststo: quietly rreg z2_elect_loss z2_misery z2_wevent if east == 0
eststo: quietly rreg z2_elect_loss c.z2_misery##c.z2_wevent if east == 0

esttab using table_b16.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery and protest on electoral loss (robust regression))

**---------------------------------------
** appendix c-2: analyse impact of elections on protest

eststo clear

eststo: reg z2_react_wevent z2_misery
eststo: reg z2_react_wevent z2_misery z2_elect_loss
eststo: reg z2_react_wevent c.z2_misery##c.z2_elect_loss

eststo: reg z2_react_wevent z2_misery if east == 0
eststo: reg z2_react_wevent z2_misery z2_elect_loss  if east == 0 
eststo: reg z2_react_wevent c.z2_misery##c.z2_elect_loss if east == 0

esttab using table_c4.rtf, b(2) t(2) r2(2) nogaps nobaselevels label replace ///
starlevels(+ 0.1 * 0.05 ** 0.01 *** 0.001) ///
title(The impact of economic misery and electoral loss on protest)

**---------------------------------------
*** appendix: marginal effect plots
**---------------------------------------

cd "../graphs/"

** figure c-4a: marginal effect of protest on electoral loss across the range of economic misery (all)
regress z2_elect_loss c.z2_wevent##c.z2_misery
margins, dydx(z2_wevent) at(z2_misery=(-2.5(0.1)3.5))
marginsplot, xsize(6) ysize(5) xlabel(-2.5 (1) 3.5) level(95) title("") ytitle("Average marginal effect of protest", size(medlarge)) recast(line) recastci(rarea) ciopts(color(*.5)) yline(0) ylabel(,labsize(medlarge)) xlabel(,labsize(medlarge)) xtitle(,size(medlarge))
graph export figure_c1a.eps, replace

** figure c-4b: marginal effect of protest on electoral loss across the range of economic misery (west europe)
regress z2_elect_loss c.z2_wevent##c.z2_misery if east == 0
margins, dydx(z2_wevent) at(z2_misery=(-2.5(0.1)3.5))
marginsplot, xsize(6) ysize(5) ylabel(-1 (0.5) 1) xlabel(-2.5 (1) 3.5) level(95) title("") ytitle("Average marginal effect of protest", size(medlarge)) recast(line) recastci(rarea) ciopts(color(*.5)) yline(0) ylabel(,labsize(medlarge)) xlabel(,labsize(medlarge)) xtitle(,size(medlarge))
graph export figure_c1b.eps, replace
